package com.tools.web.work.excel.poi;

import com.tools.common.container.AbsOwnList;
import com.tools.common.io.IOKit;
import com.tools.common.object.C;
import com.tools.common.object.Note;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 导入 Excel 文件的构建对象
 * */
@Note("导入 Excel 文件的构建对象")
public final class ExcelImportBuilder {

    @Note("已读取的目标 Excel 文件")
    private Workbook workbook;

    @Note("当前使用中的 Sheet 的索引")
    private int currentUseSheetIndex = 0;

    @Note("Sheet 页结构列表。每个 Sheet 页对应其中的一个")
    private List<SheetImportBuilder> sheetImportBuilderList;

    @Note("读取的 Excel 文件的类型")
    private ExcelTypeEnum excelType;

    @Note("开始读取的行号（从 0 开始）")
    private int startRow;

    @Note("结束读取的行号（从 0 开始）。")
    private int endRow;

    /* ************************************************************************************************************
     *
     *      构造器
     *
     * ************************************************************************************************************
     * */

    public ExcelImportBuilder(InputStream excelFile, SheetImportBuilder sheetImportBuilder) {
        private_initWorkbook(ExcelTypeEnum.XSSF, excelFile);
        private_initSheetList(sheetImportBuilder);
    }

    public ExcelImportBuilder(InputStream excelFile, SheetImportBuilder... sheetImportBuilderArray) {
        private_initWorkbook(ExcelTypeEnum.XSSF, excelFile);
        private_initSheetList(sheetImportBuilderArray);
    }

    public ExcelImportBuilder(InputStream excelFile, List<SheetImportBuilder> sheetImportBuilderList) {
        private_initWorkbook(ExcelTypeEnum.XSSF, excelFile);
        private_initSheetList(sheetImportBuilderList);
    }

    public ExcelImportBuilder(InputStream excelFile, AbsOwnList<SheetImportBuilder> sheetImportBuilderList) {
        private_initWorkbook(ExcelTypeEnum.XSSF, excelFile);
        private_initSheetList(sheetImportBuilderList);
    }

    public ExcelImportBuilder(ExcelTypeEnum excelType, InputStream excelFile, SheetImportBuilder sheetImportBuilder) {
        private_initWorkbook(excelType, excelFile);
        private_initSheetList(sheetImportBuilder);
    }

    public ExcelImportBuilder(ExcelTypeEnum excelType, InputStream excelFile, SheetImportBuilder... sheetImportBuilderArray) {
        private_initWorkbook(excelType, excelFile);
        private_initSheetList(sheetImportBuilderArray);
    }

    public ExcelImportBuilder(ExcelTypeEnum excelType, InputStream excelFile, List<SheetImportBuilder> sheetImportBuilderList) {
        private_initWorkbook(excelType, excelFile);
        private_initSheetList(sheetImportBuilderList);
    }

    public ExcelImportBuilder(ExcelTypeEnum excelType, InputStream excelFile, AbsOwnList<SheetImportBuilder> sheetImportBuilderList) {
        private_initWorkbook(excelType, excelFile);
        private_initSheetList(sheetImportBuilderList);
    }

    public static ExcelImportBuilder of(InputStream excelFile, SheetImportBuilder sheetImportBuilder) {
        return new ExcelImportBuilder(excelFile, sheetImportBuilder);
    }

    public static ExcelImportBuilder of(InputStream excelFile, SheetImportBuilder... sheetImportBuilderArray) {
        return new ExcelImportBuilder(excelFile, sheetImportBuilderArray);
    }

    public static ExcelImportBuilder of(InputStream excelFile, List<SheetImportBuilder> sheetImportBuilderList) {
        return new ExcelImportBuilder(excelFile, sheetImportBuilderList);
    }

    public static ExcelImportBuilder of(InputStream excelFile, AbsOwnList<SheetImportBuilder> sheetImportBuilderList) {
        return new ExcelImportBuilder(excelFile, sheetImportBuilderList);
    }

    public static ExcelImportBuilder of(ExcelTypeEnum excelType, InputStream excelFile, SheetImportBuilder sheetImportBuilder) {
        return new ExcelImportBuilder(excelType, excelFile, sheetImportBuilder);
    }

    public static ExcelImportBuilder of(ExcelTypeEnum excelType, InputStream excelFile, SheetImportBuilder... sheetImportBuilderArray) {
        return new ExcelImportBuilder(excelType, excelFile, sheetImportBuilderArray);
    }

    public static ExcelImportBuilder of(ExcelTypeEnum excelType, InputStream excelFile, List<SheetImportBuilder> sheetImportBuilderList) {
        return new ExcelImportBuilder(excelType, excelFile, sheetImportBuilderList);
    }

    public static ExcelImportBuilder of(ExcelTypeEnum excelType, InputStream excelFile, AbsOwnList<SheetImportBuilder> sheetImportBuilderList) {
        return new ExcelImportBuilder(excelType, excelFile, sheetImportBuilderList);
    }

    @Override
    public String toString() {
        return "ExcelImportBuilder{" +
                "workbook=" + workbook +
                ", currentUseSheetIndex=" + currentUseSheetIndex +
                ", excelType=" + excelType +
                ", startRow=" + startRow +
                ", endRow=" + endRow +
                ", sheetImportBuilderList=" + sheetImportBuilderList +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ExcelImportBuilder that = (ExcelImportBuilder) o;
        return Objects.equals(workbook, that.workbook) && excelType == that.excelType;
    }

    @Override
    public int hashCode() {
        return Objects.hash(workbook, excelType);
    }

    /* ************************************************************************************************************
     *
     *      工具方法
     *
     * ************************************************************************************************************
     * */

    public ExcelTypeEnum getExcelType() {
        return excelType;
    }

    public int getCurrentUseSheetIndex() {
        return currentUseSheetIndex;
    }

    public ExcelImportBuilder useSheet(int index) {
        int numberOfSheets = this.workbook.getNumberOfSheets();
        if(index >= 0 && index < numberOfSheets) {
            this.currentUseSheetIndex = index;
            return this;
        }
        throw new ArrayIndexOutOfBoundsException("工作表数量为 " + numberOfSheets
                + "，当前要使用的表索引: " + this.currentUseSheetIndex);
    }

    public ExcelImportBuilder nextSheet() {
        int numberOfSheets = this.workbook.getNumberOfSheets();
        int index = this.currentUseSheetIndex + 1;
        if(index < numberOfSheets) {
            this.currentUseSheetIndex = index;
        }
        return this;
    }

    public ExcelImportBuilder previousSheet() {
        int numberOfSheets = this.workbook.getNumberOfSheets();
        int index = this.currentUseSheetIndex - 1;
        if(index >= 0 && index < numberOfSheets) {
            this.currentUseSheetIndex = index;
        }
        return this;
    }

    public ExcelImportBuilder startRow(int startRow) {
        this.startRow = startRow;
        return this;
    }

    public ExcelImportBuilder readSize(int size) {
        this.endRow = this.startRow + size;
        return this;
    }

    public Map<Integer, ExcelImg> readImageOfSheet() {
        Sheet sheet = this.workbook.getSheetAt(this.currentUseSheetIndex);
        return ExcelKit.readImgAsColumnIndexMap(sheet);
    }

    public <T> List<T> read(C<T> dataType) {
        Sheet sheet = this.workbook.getSheetAt(this.currentUseSheetIndex);
        return private_read(dataType, sheet, this.currentUseSheetIndex, this.startRow, this.endRow);
    }


    public <T> List<T> readAllSheet(C<T> dataType) {
        int numberOfSheets = this.workbook.getNumberOfSheets();
        List<T> result = new ArrayList<>();
        for (int i = 0; i < numberOfSheets; i++) {
            Sheet sheet = this.workbook.getSheetAt(i);
            List<T> data = private_read(dataType, sheet, i, 0, -1);
            result.addAll(data);
        }
        return result;
    }


    public void close() {
        IOKit.close(this.workbook);
    }

    /* ************************************************************************************************************
     *
     *      私有逻辑
     *
     * ************************************************************************************************************
     * */

    @Note("初始化 Workbook 对象")
    private void private_initWorkbook(ExcelTypeEnum excelType, InputStream excelFile) {
        if(excelType == null) throw new NullPointerException("Excel 类型枚举实例不能为 null");
        this.workbook = ExcelKit.newWorkbook(excelType, excelFile);
        this.excelType = excelType;
    }

    @Note("初始化 Sheet 页的结构 List 集合")
    private void private_initSheetList(SheetImportBuilder sheetImportBuilder) {
        if(sheetImportBuilder == null) throw new NullPointerException("SheetImportBuilder 对象为 null");
        if(this.sheetImportBuilderList == null) {
            this.sheetImportBuilderList = new ArrayList<>(1);
        }
        this.sheetImportBuilderList.add(sheetImportBuilder);
    }

    @Note("初始化 Sheet 页的结构 List 集合")
    private void private_initSheetList(SheetImportBuilder... sheetImportBuilderArray) {
        if(sheetImportBuilderArray == null) throw new IllegalArgumentException("SheetImportBuilder 数组为空");
        int length = sheetImportBuilderArray.length;
        if(length == 0) throw new IllegalArgumentException("至少需要一个以上的 SheetImportBuilder 对象参数");
        this.sheetImportBuilderList = new ArrayList<>(length);
        for (SheetImportBuilder builder : sheetImportBuilderArray) {
            private_initSheetList(builder);
        }
    }

    @Note("初始化 Sheet 页的结构 List 集合")
    private void private_initSheetList(List<SheetImportBuilder> sheetImportBuilderList) {
        if(sheetImportBuilderList == null || sheetImportBuilderList.isEmpty()) {
            throw new IllegalArgumentException("SheetImportBuilder 的列表为空");
        }
        this.sheetImportBuilderList = new ArrayList<>(sheetImportBuilderList.size());
        for (SheetImportBuilder builder : sheetImportBuilderList) {
            private_initSheetList(builder);
        }
    }


    @Note("初始化 Sheet 页的结构 List 集合")
    private void private_initSheetList(AbsOwnList<SheetImportBuilder> sheetImportBuilderList) {
        if(sheetImportBuilderList == null || sheetImportBuilderList.isEmpty()) {
            throw new IllegalArgumentException("SheetImportBuilder 的列表为空");
        }
        this.sheetImportBuilderList = new ArrayList<>(sheetImportBuilderList.size());
        for (SheetImportBuilder builder : sheetImportBuilderList) {
            private_initSheetList(builder);
        }
    }


    @Note("读取操作")
    private <T> List<T> private_read(C<T> dataType, Sheet sheet, int currentUseSheetIndex, int start, int end) {
        SheetImportBuilder builder = this.sheetImportBuilderList.get(currentUseSheetIndex);
        Map<Integer, String> indexAndFieldMap = builder.getIndexAndFieldMap(sheet);
        return ExcelKit.readToListByRow(sheet, builder.getExcelHead(), dataType,
                indexAndFieldMap, start, end);
    }
}
